var recluseFile = "% This is an *emphasis* and *other emphasis*. \n\n% The book of Programming.\n\n% this is a footnote {I am footnote}."

var paragraphs = recluseFile.split("\n\n");
//document.write("paragraph num is " + paragraphs.length + ".");
//document.write('<br>');
function asArray(quasiArray, start)
{
	var result = [];
	for( var i = (start || 0); i<quasiArray.length; i++)
	{
		result.push(quasiArray[i]);
	}
	return result;
}

function partial(func, argument)
{
	var fixedArgs = asArray(argument, 1);
	return function()
	{
		return func.apply(null, fixedArgs.concat(asArray(arguments)));
	};	
}
var op = {
	"+": function(a, b){return a+b;},
	"-": function(a, b){return a-b;}
};

var rst = map(partial(op["+"], 1), [0, 2, 4, 6, 10]);
for(var i = 0; i<rst.length; ++i)
{
	document.write(rst[i]);
}
print(rst);




function renderParagraph(paragraph)
{
	return tag(paragraph.type, map(renderFragment, paragraph.content));
}


var linkObj = link("http://www.nedroid.com", "Drawings!");
for (var k in linkObj)
{
	document.write(k + " : ");
	document.write(linkObj[k]);
	document.write('<br>');
}

var str = renderHTML(linkObj);
document.write(str);

function print(table)
{
	document.write("begin a table");
	document.write('<br>');
	for (var t in table)
	{
		document.write(t + " : ");
		document.write(table[t]);
		document.write('<br>');		
	}
	document.write("end a table");
	document.write('<br>');
}

function renderHTML(element) {
  var pieces = [];

  function renderAttributes(attributes) {
    var result = [];
    if (attributes) {
      for (var name in attributes) 
        result.push(" " + name + "=\"" +
                    escapeHTML(attributes[name]) + "\"");
    }
    return result.join("");
  }

  function render(element) {
    // Text node
    if (typeof element == "string") {
      pieces.push(escapeHTML(element));
    }
    // Empty tag
    else if (!element.content || element.content.length == 0) {
      pieces.push("<" + element.name +
                  renderAttributes(element.attributes) + "/>");
    }
    // Tag with content
    else {
      pieces.push("<" + element.name +
                  renderAttributes(element.attributes) + ">");
      forEach(element.content, render);
      pieces.push("</" + element.name + ">");
    }
  }

  render(element);
  return pieces.join("");
}

function link(target, text)
{
	return tag("a", {href:target}, [text])
}
function htmlDoc(title, bodyContent)
{
	return tag("html", [tag("head", [tag("title", [title])]), 
	                    tag("body",	bodyContent)]);
}

var linkObject = {name:"a",
				  attributes: {href: "http://www.gokgs.com/"},
				  content: ["Play Go!"]};

//<img src="img/ostrich.png"/>
function escapeHTML(text)
{
	var replacements = [[/&/g, "&amp;"], [/"/g, "&quot;"],
                      [/</g, "&lt;"], [/>/g, "&gt;"]];
    forEach(replacements, function(replace)
    {
		text = text.replace(replace[0], replace[1]);
	})
	return text;
}


function tag(name, attributes, content)
{
	return {name: name, attributes:attributes, content:content};
}				  
				  



function splitParagraph(text)
{
	function indexOrEnd(character) //get end index or end
	{
		var index = text.indexOf(character);		
		return index == -1 ? text.length: index;
	}
	
	function takeNormal() //return first normal part and reduce text
	{
		var end = reduce(Math.min, text.length, map(indexOrEnd, ["*", "{"]));
		//var end = indexOrEnd('*');
		var part = text.slice(0, end);
		text = text.slice(end);		
		return part;
	}
	
	function takeUpTo(character)  //find the end of * or }
	{
		var end = text.indexOf(character, 1);		
		if (end == -1)
		{			
			throw new Error("Missing chosing '" + character + "'");
		}
		var part = text.slice(1, end);
		text = text.slice(end+1);
		return part;
	}
	
	var fragments = [];
	while( text != "")
	{
		if(text.charAt(0) == "*")
		{
			fragments.push({type:"emphasised",
			                content: takeUpTo("*")
			                });			
		}
		else if(text.charAt(0) == "{")
		{
			fragments.push({type:"footnote",
						    content: takeUpTo("}")
						    });			
		}
		else
		{
			fragments.push({type:"normal",
						    content: takeNormal()
						    });			
		}
	}
	
	return fragments;
}

function processParagraph(paragraph)
{	
	var header = 0;	
	while(paragraph.charAt(header) == '%')
	{
		header++;
	}
	paragraph = paragraph.slice(header);
	
	var ret = {type: (header == 0 ?"p":"h"+header), 
	        content: splitParagraph(paragraph)};
   /* 	        
	for (c in ret.content)
	{
		document.write(ret.content[c].type);
		document.write(ret.content[c].content);
		document.write('<br>');
	}*/
	
	return ret;	
}

function extractFootnotes(paragraphs) {
  var footnotes = [];
  var currentNote = 0;

	
  function replaceFootnote(fragment) {	 
    if (fragment.type == "footnote") {
      currentNote++;
      footnotes.push(fragment.content);
      fragment.number = currentNote;
      return {type: "reference", number: currentNote};
    }
    else {
      return fragment;
    }
  }
  
  map(replaceFootnote, paragraphs.content);  
  return footnotes;
} 


//var para = 
var para = processParagraph(paragraphs[2]);

var footnotes = extractFootnotes(para);
for (f in footnotes)
{
	document.write(f);
	document.write('<br>');
	if(footnotes.hasOwnProperty(f))
	{
		document.write(f + ": ");
		document.write(footnotes[f]);
		document.write('<br>');		
	}
}

function map(func, array)
{	
	var result = [];
	forEach(array, function(element){
		result.push(func(element));
	});
	return result;
}

function forEach(array, action)
{
	for(var i = 0; i<array.length; i++)
	{
		action(array[i]);
	}
}

function reduce(combine, base, array)
{
	forEach(array, function(element)
	{
		base = combine(base, element);
	});
	return base;
}

//document.write(para['type']);

/*

var rst = map(Math.round, [0.01, 2, 9.89, Math.PI]);
//document.write(rst);

function count(array, func)
{
	base = 0;
	forEach(array, function(element)
	{
		(func(element) == true)? base+=1: 0;		
	});
	return base;		
}



function add(a, b)
{
	return a+b;
}
function countZeros(a)
{
	return a == 0;
}

var k = reduce(add, 0, [1, 2, 4]);
//document.write(k);
var zeroNum = count([0, 0, 0, 1], countZeros);
//document.write(zeroNum);



//document.write(Math.min.apply(null, [5,6]));

function negate(func)
{
	return function()
	{
		return !func.apply(null, arguments);
	};
}

function negate(func)
{
	return function(x)
	{
		return !func(x);
	};
}
var isNotNaN = negate(isNaN);
//document.write(isNotNaN(NaN));

function sum(numbers)
{
	var total = 0;
	forEach(numbers, function(number)
	{
		total += number;
	});
	return total;
}
//document.write(sum([1, 10, 1000]));
	
function printArray(array)
{
	for (var i = 0; i<array.length; i++)
	{
		document.write(array[i]);
	}
}


*/
